package org.jetnuke.common;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import javax.servlet.ServletContext;

import net.jforum.DBConnection;
import net.jforum.JForumExecutionContext;
import net.jforum.util.FileChangeListener;
import net.jforum.util.FileMonitor;
import net.jforum.util.preferences.ConfigKeys;
import net.jforum.util.preferences.SystemGlobals;
import net.n3.nanoxml.IXMLElement;
import net.n3.nanoxml.IXMLParser;
import net.n3.nanoxml.IXMLReader;
import net.n3.nanoxml.StdXMLReader;
import net.n3.nanoxml.XMLParserFactory;

import org.apache.log4j.Logger;
import org.jetnuke.dao.DataAccessDriver;
import org.jetnuke.entities.Blocks;
import org.jetnuke.entities.Modules;

public class Configuration {
	static ServletContext context;
	final static Logger s_log = Logger.getLogger(Configuration.class);
	static private FileChangeListener fcl = new FileChangeListener() {
		public void fileChanged(String filename) {

			Connection conn = null;
			try {
				conn = DBConnection.getImplementation().getConnection();
				JForumExecutionContext ex = JForumExecutionContext.get();
				ex.setConnection(conn);
				JForumExecutionContext.set(ex);
				System.out.println("File Changed:" + filename);
				Configuration cfg = new Configuration(context);
				context.setAttribute("_cfg", cfg);
			} catch (Throwable t) {
				s_log.error(t);
			} finally {
				if (conn != null)
					try {
						DBConnection.getImplementation()
								.releaseConnection(conn);
					} catch (Throwable t) {

						s_log.error(t);
					}
			}
		}
	};
	

	public Configuration(ServletContext context) {
		Configuration.context = context;
		loadBlocks();
		loadModules();
	}

	public ArrayList<IBlockInfo> blocks = new ArrayList<IBlockInfo>();

	public Hashtable<String,ModuleInfo> modules = new Hashtable<String,ModuleInfo>();

	private void loadBlocks() {

		Iterator<Blocks> it = null;
		try {
			it = DataAccessDriver.getInst().newBlockDAO().selectAllByWeight()
					.iterator();

		} catch (Exception e) {
			s_log.error(e);

		}
		if (it != null)
			while (it.hasNext()) {
				Blocks blc = (Blocks) it.next();
				IBlockInfo ib = loadBlock(blc);
				if (ib != null)
					blocks.add(ib);
			}

	}

	private IBlockInfo loadBlock(Blocks blc) {
		BlockInfo bInfo = new BlockInfo();
		try {
			bInfo.setActivated(blc.getACTIVE() == 1);
			if (blc.getBKEY() != null && blc.getBKEY().equals("admin")) {
				bInfo.setAdminOnly(true);
			} else if (blc.getBKEY() != null
					&& blc.getBKEY().equals("anonymous")) {
				bInfo.setAnonymousOnly(true);
			} else if (blc.getBKEY() != null && blc.getBKEY().equals("user")) {
				bInfo.setUserOnly(true);
			}
			String path = blc.getPATH();
			bInfo.setBid(blc.getBID());
			bInfo.setPosition(blc.getPOSITION());

			bInfo.setBlockClass("org.jetnuke.common.BasicBlock");
			bInfo.setTemplateName("block.vm");
			bInfo.setActivated(blc.getACTIVE() == 1);
			bInfo.setTitle(blc.getTITLE());
			bInfo.setRssUrl(blc.getRSS_URL());

			if (!"".equals(path)) {
				String xmlPath = "/blocks/" + path;
				if (!xmlPath.endsWith("/"))
					xmlPath = xmlPath + "/";
				// URL url = getClass().getClassLoader().getResource(
				// xmlPath + "config.xml");

				File f = new File(context.getRealPath("") + "/WEB-INF/"
						+ xmlPath + "config.xml");// context.getsgetClass().getClassLoader().getResource(

				int fileChangesDelay = SystemGlobals
						.getIntValue(ConfigKeys.FILECHANGES_DELAY);
				if (f.exists())
					FileMonitor.getInstance().addFileChangeListener(fcl,
							f.getAbsolutePath(), fileChangesDelay);
				StringBuffer buf = readFile(f);
				IXMLReader reader = StdXMLReader.stringReader(buf.toString());
				IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
				// IXMLReader reader=StdXMLReader.fileReader(url.getFile());
				parser.setReader(reader);
				IXMLElement xml = (IXMLElement) parser.parse();
				Vector v = xml.getChildrenNamed("name");
				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					bInfo.setName(el.getContent());
				}
				v = xml.getChildrenNamed("description");

				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					bInfo.setDescription(el.getContent());
				}
				v = xml.getChildrenNamed("block-class");

				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					bInfo.setBlockClass(el.getContent());
				}
				v = xml.getChildrenNamed("template");

				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					bInfo.setTemplateName(el.getContent());
				}
				v = xml.getChildrenNamed("param");

				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					bInfo.putParam(el.getAttribute("name", null), el
							.getContent());
				}
				bInfo.setPath(xmlPath);
			} else {
				bInfo.setPath("");
				bInfo.setContent(blc.getCONTENT());
			}

		} catch (Throwable e) {

			s_log.error(e);
			bInfo.setValid(false);
		}
		if (bInfo.isValid())
			return bInfo;
		return null;

	}

	protected void loadModules() {
		AdminModuleInfo adminInfo = loadAdminModule("/modules/admin/");
		adminInfo.setActive(true);
		modules.put("admin", adminInfo);

		Iterator it = null;
		try {
			it = DataAccessDriver.getInst().newModulesDAO().selectAll()
					.iterator();
		} catch (Exception e) {
			s_log.error(e);

		}
		if (it != null) {
			while (it.hasNext()) {
				Modules module = (Modules) it.next();
				ModuleInfo iModInfo = loadModule("/modules/" + module.getPATH()
						+ "/");
				if (iModInfo != null) {
					iModInfo.setActive(module.getACTIVE() == 1);
					iModInfo.setModuleRole(module.getBKEY());
					modules.put(module.getPATH(), iModInfo);
				}
			}
		}

	}

	/**
	 * @param string
	 * @return
	 */
	private AdminModuleInfo loadAdminModule(String xmlPath) {
		AdminModuleInfo mInfo = null;
		try {
			mInfo = new AdminModuleInfo();
			IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
			// URL url = getClass().getClassLoader().getResource(
			// xmlPath + "config.xml");

			File f = new File(context.getRealPath("") + "/WEB-INF/" + xmlPath
					+ "config.xml");// context.getsgetClass().getClassLoader().getResource(

			int fileChangesDelay = SystemGlobals
					.getIntValue(ConfigKeys.FILECHANGES_DELAY);
			if (f.exists())
				FileMonitor.getInstance().addFileChangeListener(fcl,
						f.getAbsolutePath(), fileChangesDelay);
			StringBuffer buf = readFile(f);
			IXMLReader reader = StdXMLReader.stringReader(buf.toString());

			parser.setReader(reader);
			IXMLElement xml = (IXMLElement) parser.parse();
			Vector v = xml.getChildrenNamed("action");
			for (int i = 0; i < v.size(); i++) {
				IXMLElement el = (IXMLElement) v.get(i);
				String actionName = el.getAttribute("name", null);
				String className = el.getAttribute("class", null);
				mInfo.putAction(actionName, className, null);
				String page = el.getAttribute("page", null);
				if (page == null) {
					page = "";
				}
				mInfo.putPage(actionName, page);
			}
			v = xml.getChildrenNamed("defaction");
			for (int i = 0; i < Math.min(v.size(), 1); i++) {
				IXMLElement el = (IXMLElement) v.get(i);
				// Node classNode = node.getAttributes().getNamedItem("class");
				String className = el.getAttribute("class", null);
				mInfo.setDefaultAction(className);

				String page = el.getAttribute("page", null);
				if (page == null)
					page = "";
				mInfo.putPage("", page);

			}
			v = xml.getChildrenNamed("forward");

			for (int i = 0; i < v.size(); i++) {
				IXMLElement el = (IXMLElement) v.get(i);

				String role = null;
				mInfo.putForward(el.getAttribute("name", null), el
						.getAttribute("page", null), role);
			}

			mInfo.setPath(xmlPath);
		} catch (Exception e) {
			s_log.error(e);
		}
		return mInfo;

	}

	private ModuleInfo loadModule(String xmlPath) {
		if (!xmlPath.endsWith("/"))
			xmlPath = xmlPath + "/";
		ModuleInfo mInfo = null;
		try {
			mInfo = new ModuleInfo();
			File f = new File(context.getRealPath("") + "/WEB-INF/" + xmlPath
					+ "config.xml");// context.getsgetClass().getClassLoader().getResource(
			// xmlPath + "config.xml");
			int fileChangesDelay = SystemGlobals
					.getIntValue(ConfigKeys.FILECHANGES_DELAY);
			if (f.exists()) {

				FileMonitor.getInstance().addFileChangeListener(fcl,
						f.getAbsolutePath(), fileChangesDelay);
				StringBuffer buf = readFile(f);
				IXMLReader reader = StdXMLReader.stringReader(buf.toString());
				IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
				parser.setReader(reader);
				IXMLElement xml = (IXMLElement) parser.parse();
				Vector v = xml.getChildrenNamed("action");
				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					String actionName = el.getAttribute("name", null);
					String className = el.getAttribute("class", null);
					String role = el.getAttribute("role", null);
					mInfo.putAction(actionName, className, role);
					String page = el.getAttribute("page", null);
					if (page == null) {
						page = "";
					}
					mInfo.putPage(actionName, page);
				}
				v = xml.getChildrenNamed("defaction");
				for (int i = 0; i < Math.min(v.size(), 1); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					// Node classNode =
					// node.getAttributes().getNamedItem("class");
					String className = el.getAttribute("class", null);
					mInfo.setDefaultAction(className);

					String page = el.getAttribute("page", null);
					if (page == null)
						page = "";
					mInfo.putPage("", page);

				}
				v = xml.getChildrenNamed("classModule");
				for (int i = 0; i < Math.min(v.size(), 1); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					// Node classNode =
					// node.getAttributes().getNamedItem("class");
					String classModule = el.getAttribute("class", null);
					try {
						Class clazz = Class.forName(classModule);
						Class[] interfaces = clazz.getInterfaces();
						if (Arrays.asList(interfaces).contains(
								ICustomModule.class)) {
							mInfo.setHasModuleClass(true);
							mInfo.setModuleClass(clazz);
						}
					} catch (Throwable t) {
						s_log.error(t);
					}
				}
				v = xml.getChildrenNamed("forward");
				for (int i = 0; i < v.size(); i++) {
					IXMLElement el = (IXMLElement) v.get(i);
					// Node nRole = node.getAttributes().getNamedItem("role");
					String role = el.getAttribute("role", null);
					// if (nRole != null) {
					// role = nRole.getNodeValue();
					// }
					mInfo.putForward(el.getAttribute("name", null), el
							.getAttribute("page", null), role);
				}

				mInfo.setPath(xmlPath);
			}
		} catch (Throwable e) {
			System.out.println("Error loading " + xmlPath);
			s_log.error(e);
			mInfo = null;
		}
		return mInfo;
	}

	private StringBuffer readFile(File fileName) {
		StringBuffer buf = new StringBuffer(1000);
		try {
			BufferedReader in = new BufferedReader(new FileReader(fileName));
			String str;
			while ((str = in.readLine()) != null) {
				buf.append(str);
			}
			in.close();
		} catch (IOException e) {
		}
		return buf;
	}
}